package com.tevintao.marketingsystem.xposted;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Process;
import android.util.Log;

import com.tevintao.marketingsystem.log.LogManager;
import com.tevintao.marketingsystem.services.AccountManager;
import com.tevintao.marketingsystem.services.MockServices;
import com.tevintao.marketingsystem.task.WxTaskProcess;
import com.tevintao.marketingsystem.task.WxUiViewConfig;

import org.json.JSONArray;
import org.json.JSONException;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.IXposedHookZygoteInit;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;

public class HookDeviceModule implements IXposedHookLoadPackage, IXposedHookZygoteInit {

    public static final String TAG = HookDeviceModule.class.getSimpleName();

    public static final String LOG_TAG = "ttw";

    public static final String SELF_PACKAGE_NAME = "com.tevintao.marketingsystem";
    public static final String XPOSED_PACKAGE_NAME = "de.robv.android.xposed.installer";

    public static final String SETTINGS_PACKAGE_NAME = "com.android.settings";

    public static final String CONTACTS_PACKAGE_NAME = "com.android.providers.contacts";


    @Override
    public void handleLoadPackage(LoadPackageParam loadPackageParam) throws Throwable {
        if (loadPackageParam.appInfo == null || (loadPackageParam.appInfo.flags & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
            Log.i(LOG_TAG, "系统app" + loadPackageParam.packageName);
            if (loadPackageParam.isFirstApplication && SETTINGS_PACKAGE_NAME.equals(loadPackageParam.packageName)) {
            }
            return;
        } else if (loadPackageParam.isFirstApplication && SELF_PACKAGE_NAME.equals(loadPackageParam.packageName)) {
//            HookDeviceInfo.getInstance().hookSystemProperties();
            LogManager.getInstance().logInfo("SELF_PACKAGE_NAME = " + SELF_PACKAGE_NAME);
//            HookPackageManager.getInstance().hookPackageManager(loadPackageParam);

//            LogManager.getInstance().logInfo("MainActivity testHookHook ");
//            hookAllMethodByName(MainActivity.class, "testHookHook", hhh);

/*

            Class contextImpl = null;
            try {
                contextImpl = loadPackageParam.classLoader.loadClass("android.app.ContextImpl");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            LogManager.getInstance().logInfo("contextImpl = " + contextImpl);

            if (null != contextImpl) {
                XposedBridge.hookAllConstructors(contextImpl, new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        super.beforeHookedMethod(param);
                        StringBuilder sb = new StringBuilder();
                        for (int i = 0, len = param.args.length; i < len; i++) {
                            sb.append(" index i = " + i + "" + param.args[i]);
//                            if (param.args[i].getClass().getName().equals("android.app.LoadedApk")) {
//                                LogManager.getInstance().logInfo("contextImpl 找到loadapk");
//                            }
                        }
                        LogManager.getInstance().logInfo("contextImpl method = " + param.method.getName() + " thisObject " + param.thisObject + " getResult " + param.getResult() + " params = " + sb.toString());
//                        Field[] declaredFields = loadedApkCls.getDeclaredFields();
//                        for (Field field : declaredFields) {
//                            field.setAccessible(true);
//                        }
                    }
                });
            }
*/

/*

            hookAllMethodByName(Display.class, "getWidth", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    Object result = param.getResult();
                    LogManager.getInstance().logInfo("getWidth = " + result);
                    param.setResult(20);
                }
            });

            hookAllMethodByName(Display.class, "getHeight", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    Object result = param.getResult();
                    LogManager.getInstance().logInfo("getHeight = " + result);
                    param.setResult(30);
                }
            });

            hookAllMethodByName(Display.class, "getMetrics", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    LogManager.getInstance().logInfo("Display getMetrics ");
                    for (Object po : param.args) {
                        if (po instanceof DisplayMetrics) {
                            DisplayMetrics dm = (DisplayMetrics) po;
                            dm.widthPixels = 60;
                            dm.heightPixels = 70;
                        }
                        LogManager.getInstance().logInfo("po = " + po);
                    }
                }
            });

            hookAllMethodByName(Resources.class, "getDisplayMetrics", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    if (param.getResult() instanceof DisplayMetrics) {
                        DisplayMetrics dm = (DisplayMetrics) param.getResult();
                        dm.widthPixels = 80;
                        dm.heightPixels = 90;
                        dm.xdpi = 10;
                        dm.ydpi = 11;
                        dm.densityDpi=12;
                        dm.density = 13;
                        dm.scaledDensity = 14;
                    }
                }
            });
*/

        } else if (loadPackageParam.isFirstApplication && CONTACTS_PACKAGE_NAME.equals(loadPackageParam.packageName)) {
            LogManager.getInstance().logInfo("hook CONTACTS_PACKAGE_NAME = " + CONTACTS_PACKAGE_NAME);
        } else if (loadPackageParam.isFirstApplication && AccountManager.WX_PACKAGE_NAME.equals(loadPackageParam.packageName)) {

            if (AccountManager.CURREN_DEVICE_TYPE == AccountManager.TYPE_NO_DEVICE_INFO) {
                LogManager.getInstance().logInfo("不需要获取设备i 信息");
            } else {
                boolean loadDeviceInfo = WXDeviceManager.getInstance().loadDeviceFromCache();
                if (!loadDeviceInfo) {
                    LogManager.getInstance().logError("loadDeviceInfo Error !!!!!!!!!");
                    System.exit(0);
                    Process.killProcess(Process.myPid());
                } else {
                    LogManager.getInstance().logInfo("load device info success ");
                }
            }

//            if (MockServices.checkClient()) {
//                try {
//                    mCurrentAccountSdPath = MockServices.getClient().getAccountPhone();
//                } catch (RemoteException e) {
//                    e.printStackTrace();
//                }
//            } else {
//                LogManager.getInstance().logError("!MockServices.checkClient()");
//                System.exit(0);
//                Process.killProcess(Process.myPid());
//            }
//            if (TextUtils.isEmpty(mCurrentAccountSdPath)) {
//                LogManager.getInstance().logError("TextUtils.isEmpty(mCurrentAccountSdPath)");
//                System.exit(0);
//                Process.killProcess(Process.myPid());
//            }


//            boolean update = false;
//            if (MockServices.checkClient()) {
//                update = MockServices.getClient().updateDeviceJsonFromLocal();
//            } else {
//                LogManager.getInstance().logError("!MockServices.checkClient() update");
//                System.exit(0);
//                Process.killProcess(Process.myPid());
//            }
//
//            if (!update) {
//                LogManager.getInstance().logError("update device error");
//                System.exit(0);
//                Process.killProcess(Process.myPid());
//            } else {
//                LogManager.getInstance().logError("update device from local success uid = " + Process.myUid() + " pid = " + Process.myPid() + " tid = " + Process.myTid());
//            }
//
//            hook(Application.class, "onCreate");
//            hook(Activity.class, "onResume");
//            hook(Activity.class, "onStop");
//            hook(Dialog.class, "show");
//            hook(Dialog.class, "dismiss");


//            HookBindServiceManager.getInstance().hookBind(loadPackageParam);

//            HookWindowManagerGlobal.getInstance().registerCallback();


//            HookWebView.getInstance().hookWebView(loadPackageParam);
//            HookWebView.getInstance().registerCallback();


//            HookRuntimeCommand.getInstance().hookCommand();

//
            HookDeviceInfo.getInstance().hookDeviceInfo();
//            if (AccountManager.CURREN_DEVICE_TYPE != AccountManager.TYPE_NO_DEVICE_INFO) {
                HookLocation.getInstance().hookLocation();
//            }
            HookPackageManager.getInstance().hookPackageManager(loadPackageParam);
            WxTaskManger.getInstance().processStart(loadPackageParam);
            hookResolver();
            HookSensor.getInstance().hookSensor();
            HookWebView.getInstance().hookWebView();
            hookFriend();

            HookAudioRecord.getInstance().hookAudioRecord();


//            hookAudioRecordConstructors();
//            hookAudioRecordRead();
//            hookWxDecoder(loadPackageParam);
//            hookAudioTract();
//            hookWxDecoder(loadPackageParam);
//            AudioTrackWrite();
//            hookGetMinBuffer();

            LogManager.getInstance().logInfo("Build.FINGERPRINT = " + Build.FINGERPRINT);
        }
    }


    public static final String KSelectImgUseTime = "KSelectImgUseTime";
    public static final String CropImage_OutputPath_List = "CropImage_OutputPath_List";

    private void hookFriend() {

        hookAllMethodByName(Activity.class, "setResult", new XC_MethodHook() {

            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
//                if ("com.tencent.mm.ui.chatting.SendImgProxyUI".equals(param.thisObject.getClass().getName())) {
//                    LogManager.getInstance().logInfo("hookFriend setResult " + param.thisObject + " obj class = " + param.thisObject.getClass() + " length =  " + param.args.length);
//
//                    for (int i = 0, len = param.args.length; i < len; i++) {
//                        LogManager.getInstance().logInfo("hookFriend params i = " + i + " obj = " + param.args[i].toString());
//                        if (param.args[i] instanceof Intent) {
//                            Intent intent = (Intent) param.args[i];
//                            int taskId = WxTaskManger.getInstance().getTaskId();
//                            LogManager.getInstance().logInfo("hookFriend 当前是改变图像 taskId = " + taskId + " intent.getExtras() = " + intent.getExtras());
//
//
//                            if (taskId == WxTaskProcess.TASK_ID_BUSINESS_CHECK) {
//                                Bundle bundle = intent.getExtras();
//                                if (null == bundle) {
//                                    LogManager.getInstance().logError("hookFriend null == bundle");
//                                } else {
//                                    ArrayList<String> newPath = new ArrayList<>();
//                                    Object picPathObj = WxTaskManger.getInstance().getExtra(WxUiViewConfig.KEY_SEND_PIC_MESSAGE);
//                                    LogManager.getInstance().logError("hookFriend picPathObj = " + picPathObj + " getProcessName = " + MockServices.getProcessName());
//                                    if (null != picPathObj) {
//                                        newPath.add(picPathObj.toString());
//                                    }
//                                    bundle.putStringArrayList(CropImage_OutputPath_List, newPath);
//                                    bundle.putLong(KSelectImgUseTime, new Random().nextInt(5000) + 1000);
//                                }
//                                intent.putExtras(bundle);
//                                LogManager.getInstance().logInfo("hookFriend 当前是改变图像 taskId = " + taskId + " intent.getExtras() = " + intent.getExtras());
//                            }
//                        }
//                    }
//                }
                if ("com.tencent.mm.plugin.gallery.ui.GalleryEntryUI".equals(param.thisObject.getClass().getName())) {
                    LogManager.getInstance().logInfo("hookFriend setResult " + param.thisObject + " obj class = " + param.thisObject.getClass() + " length =  " + param.args.length);
                    for (int i = 0, len = param.args.length; i < len; i++) {
                        LogManager.getInstance().logInfo("hookFriend params i = " + i + " obj = " + param.args[i].toString());
                        if (param.args[i] instanceof Intent) {
                            Intent intent = (Intent) param.args[i];
                            int taskId = WxTaskManger.getInstance().getTaskId();
                            if (taskId == WxTaskProcess.TASK_ID_SEND_FRIEND_CIRCLE) {
                                Bundle bundle = intent.getExtras();
                                if (null == bundle) {
                                    LogManager.getInstance().logError("hookFriend null == bundle");
                                } else {
                                    ArrayList<String> newPath = new ArrayList<>();
                                    Object picPathObj = WxTaskManger.getInstance().getExtra(WxUiViewConfig.KEY_FRIEND_CIRCLE_PATHS);
                                    if (null != picPathObj) {
                                        try {
                                            JSONArray pathArray = new JSONArray(picPathObj.toString());
                                            for (int pathIndex = 0, PathLen = pathArray.length(); pathIndex < PathLen; pathIndex++) {
                                                String path = pathArray.getString(pathIndex);
                                                newPath.add(path);
                                                LogManager.getInstance().logInfo("hookFriend friend pic path = " + path);
                                            }
                                        } catch (JSONException e) {
                                            e.printStackTrace();
                                            LogManager.getInstance().logError("hookFriend parse path json " + e.toString());
                                        }
                                    }
                                    bundle.putStringArrayList(CropImage_OutputPath_List, newPath);
                                    bundle.putLong(KSelectImgUseTime, new Random().nextInt(5000) + 1000);
                                }
                                intent.putExtras(bundle);
                            } else if (taskId == WxTaskProcess.TASK_CHANGE_ICON) {
                                Uri data = intent.getData();
                                LogManager.getInstance().logInfo("hookFriend 当前是改变图像 data = " + data);
                                Object pathObj = WxTaskManger.getInstance().getExtra(WxUiViewConfig.CHANGE_ICON_PATH);
                                if (null != pathObj) {
                                    intent.setData(Uri.fromFile(new File(pathObj.toString())));
                                }
                            } else if (taskId == WxTaskProcess.TASK_CHANGE_FRIEND_BACK) {
                                Uri data = intent.getData();
                                LogManager.getInstance().logInfo("hookFriend 当前是改变图像 data = " + data);
                                Object pathObj = WxTaskManger.getInstance().getExtra(WxUiViewConfig.CHANGE_ICON_PATH);
                                if (null != pathObj) {
                                    intent.setData(Uri.fromFile(new File(pathObj.toString())));
                                }
                            }
                        }
                    }
                }
            }
        });
//
        hookAllMethodByName(Activity.class, "startActivityForResult", new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
                if ("com.tencent.mm.plugin.gallery.ui.ImagePreviewUI".equals(param.thisObject.getClass().getName())) {
                    LogManager.getInstance().logInfo("hookFriend startActivityForResult " + param.thisObject + " obj class = " + param.thisObject.getClass() + " length =  " + param.args.length);
                    for (int i = 0, len = param.args.length; i < len; i++) {
//                        LogManager.getInstance().logInfo("hookFriend startActivityForResult params i = " + i + " obj = " + param.args[i].toString());


                        if (param.args[i] instanceof Intent) {
                            Intent intent = (Intent) param.args[i];
                            int taskId = WxTaskManger.getInstance().getTaskId();
                            LogManager.getInstance().logInfo("hookFriend startActivityForResult taskId = " + taskId + " intent.getExtras() = " + intent.getExtras());


                            if (taskId == WxTaskProcess.TASK_ID_BUSINESS_CHECK) {
                                Bundle bundle = intent.getExtras();
                                if (null == bundle) {
                                    LogManager.getInstance().logError("hookFriend startActivityForResult null == bundle");
                                } else {
                                    ArrayList<String> newPath = new ArrayList<>();
                                    Object picPathObj = WxTaskManger.getInstance().getExtra(WxUiViewConfig.KEY_SEND_PIC_MESSAGE);
                                    LogManager.getInstance().logError("hookFriend startActivityForResult picPathObj = " + picPathObj + " getProcessName = " + MockServices.getProcessName());
                                    if (null != picPathObj) {
                                        newPath.add(picPathObj.toString());
                                    }
                                    bundle.putStringArrayList(CropImage_OutputPath_List, newPath);
                                    bundle.putLong(KSelectImgUseTime, new Random().nextInt(5000) + 1000);
                                }
                                intent.putExtras(bundle);
                                LogManager.getInstance().logInfo("hookFriend startActivityForResult taskId = " + taskId + " intent.getExtras() = " + intent.getExtras());
                            }
                        }

                    }
                }
            }
        });
////
//        hookAllMethodByName(Activity.class, "onActivityResult", new XC_MethodHook() {
//            @Override
//            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//                super.afterHookedMethod(param);
//                LogManager.getInstance().logInfo("hookFriend onActivityResult");
//                for (int i = 0, len = param.args.length; i < len; i++) {
//                    LogManager.getInstance().logInfo("hookFriend onActivityResult params i = " + i + " obj = " + param.args[i].toString());
//
//                    if (param.args[i] instanceof Intent) {
//                        Intent intent = (Intent) param.args[i];
//                        LogManager.getInstance().logInfo("hookFriend  onActivityResult intent.getExtras() = " + intent.getExtras());
//                        LogManager.getInstance().logInfo("hookFriend  onActivityResult intent.getData() = " + intent.getData());
//                    }
//                }
//            }
//        });
//        hookAllMethodByName(Activity.class, "onCreate", new XC_MethodHook() {
//            @Override
//            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//                super.afterHookedMethod(param);
//                LogManager.getInstance().logInfo("hookFriend onCreate");
//                for (int i = 0, len = param.args.length; i < len; i++) {
//                    LogManager.getInstance().logInfo("hookFriend onCreate params i = " + i + " obj = " + param.args[i].toString());
//
//                    if (param.args[i] instanceof Intent) {
//                        Intent intent = (Intent) param.args[i];
//                        LogManager.getInstance().logInfo("hookFriend  onCreate intent.getExtras() = " + intent.getExtras());
//                        LogManager.getInstance().logInfo("hookFriend  onCreate intent.getData() = " + intent.getData());
//                    }
//                }
//            }
//        });
    }


    private static final String needHookContacts = "content://com.android.contacts/data";

    private void hookResolver() {
        Method querySix = null;
        try {
            querySix = ContentResolver.class.getDeclaredMethod("query", Uri.class, String[].class, String.class, String[].class, String.class, CancellationSignal.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        if (null != querySix)
            XposedBridge.hookMethod(querySix, new XC_MethodHook() {

                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    Uri uri = Uri.parse("content://com.tevintao.contacts");
                    if (null != param.args && param.args.length > 0 && param.args[0] instanceof Uri) {
//                        LogManager.getInstance().logInfo("hookResolver uri = " + param.args[0].toString());
                        Uri wxUri = (Uri) param.args[0];
                        wxUri.getAuthority();
                        if (wxUri.toString().startsWith(needHookContacts)) {
                            param.args[0] = uri;
//                            LogManager.getInstance().logInfo("hookResolver need hook uri = " + wxUri.toString());
                        }
                    }
                    super.beforeHookedMethod(param);
                }

                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//                    LogManager.getInstance().logError("hookResover  method =  " + param.method + " getResult = " + param.getResult());
//                    if (null != param.getResult())
//                        LogManager.getInstance().logInfo("hookResover Result class = " + param.getResult().getClass().getName());
////
//                    if (null != param.getResult() && param.getResult() instanceof Cursor) {
//                        Cursor cursor = (Cursor) param.getResult();
//                        LogManager.getInstance().logInfo("hookResolver afterHookedMethod cursor count =  " + cursor.getCount());
//                    }
//                    try {
//                        if (param.thisObject instanceof ContentResolver) {
//                            ContentResolver resolver = (ContentResolver) param.thisObject;
//                            LogManager.getInstance().logInfo("hookResolver resolver = " + resolver);
//                            String params = "";
//                            for (Object po : param.args) {
//                                params += po + " - ";
//                            }
//                            if (null != resolver) {
//                                Context context = PackageTool.getResolverContext(resolver);
//                                Context rContext = context.createPackageContext(HookDeviceModule.SELF_PACKAGE_NAME, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
//                                LogManager.getInstance().logInfo("hookResolver rContext = " + rContext);
//                                Class mainAct = rContext.getClassLoader().loadClass("com.tevintao.marketingsystem.activity.MainActivity");
//                                LogManager.getInstance().logError("mainAct = " + mainAct);
//                                Method method = mainAct.getDeclaredMethod("processCursor", String.class, Object.class);
//                                method.setAccessible(true);
//                                method.invoke(null, " params = " + params, param.getResult());
//                            }
//                        }
//                    } catch (PackageManager.NameNotFoundException e) {
//                        e.printStackTrace();
//                        LogManager.getInstance().logError("hookResolver NameNotFoundException");
//                    } catch (ClassNotFoundException e) {
//                        e.printStackTrace();
//                        LogManager.getInstance().logError("hookResolver ClassNotFoundException");
//                    } catch (NoSuchMethodException e) {
//                        e.printStackTrace();
//                        LogManager.getInstance().logError("hookResolver NoSuchMethodException");
//                    } catch (IllegalAccessException e) {
//                        e.printStackTrace();
//                        LogManager.getInstance().logError("hookResolver IllegalAccessException");
//                    } catch (IllegalArgumentException e) {
//                        e.printStackTrace();
//                        LogManager.getInstance().logError("hookResolver IllegalArgumentException");
//                    } catch (InvocationTargetException e) {
//                        e.printStackTrace();
//                        LogManager.getInstance().logError("hookResolver InvocationTargetException");
//                    }

                    super.afterHookedMethod(param);
                }
            });
    }

//    private void hook(Class hookClass, final String methodName) {
//        XC_MethodHook model = new XC_MethodHook() {
//            protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
//                processObject(methodName, param.thisObject);
//            }
//        };
//        XposedHelpers.findAndHookMethod(hookClass, methodName, new Object[]{model});
//    }
//
//    private void processObject(String methodName, Object o) {
//        aViewManager.getInstance().addView(methodName, o);
//    }
//
//
//    private void hookSetting(Class hookClass, final String methodName) {
//        XC_MethodHook model = new XC_MethodHook() {
//            protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
//                processSettings(methodName, param.thisObject);
//            }
//        };
//        XposedHelpers.findAndHookMethod(hookClass, methodName, new Object[]{model});
//    }


    @Override
    public void initZygote(StartupParam startupParam) throws Throwable {
        LogManager.getInstance().logHookInfo("initZygote modulePath = " + startupParam.modulePath);

        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                Class<?> at = Class.forName("android.app.ActivityThread");
                XposedBridge.hookAllMethods(at, "systemMain", new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        try {
                            final ClassLoader loader = Thread.currentThread().getContextClassLoader();
                            Class<?> am = Class.forName("com.android.server.am.ActivityManagerService", false, loader);
                            XposedBridge.hookAllConstructors(am, new XC_MethodHook() {
                                @Override
                                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                                    try {
                                        MockServices.register(loader, param.thisObject);
                                    } catch (Throwable ex) {
                                        LogManager.getInstance().logHookError("initZygote com.android.server.am.ActivityManagerService " + ex);
                                    }
                                }
                            });
                        } catch (Throwable ex) {
                            LogManager.getInstance().logHookError("initZygote " + ex);
                        }
                    }
                });
            } else {
                Class<?> cSystemServer = Class.forName("com.android.server.SystemServer");
                Method mMain = cSystemServer.getDeclaredMethod("main", String[].class);
                XposedBridge.hookMethod(mMain, new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        try {
                            MockServices.register(null, null);
                        } catch (Throwable ex) {
                            LogManager.getInstance().logHookError("initZygote com.android.server.SystemServer beforeHookedMethod " + ex);
                        }
                    }
                });
            }
        } catch (Throwable ex) {
            LogManager.getInstance().logHookError("initZygote " + ex.getMessage());
        }

    }

//    public static void printAllMethod(Class cls) {
//        Class<?> clazz = cls;
//        String name = clazz.getSimpleName();
//        while (clazz != null) {
//            for (Method method : clazz.getDeclaredMethods()) {
//                LogManager.getInstance().logInfo(name + " method = " + method);
//            }
//            clazz = clazz.getSuperclass();
//        }
//    }

    public static void hookAllMethodByName(Class cls, String methodName, XC_MethodHook xcMethodHookhook) {
        List<Member> listMember = new ArrayList<>();
        List<Class<?>[]> listParameters = new ArrayList<>();
        Class<?> clazz = cls;
        while (clazz != null) {
            try {
                if (methodName == null) {
                    for (Constructor<?> constructor : clazz.getDeclaredConstructors())
                        if (!Modifier.isAbstract(constructor.getModifiers())
                                && Modifier.isPublic(constructor.getModifiers()))
                            listMember.add(constructor);
                    break;
                } else {
                    for (Method method : clazz.getDeclaredMethods())
                        if (method.getName().equals(methodName) && !Modifier.isAbstract(method.getModifiers())) {

                            // Check for same function in sub class
                            boolean different = true;
                            for (Class<?>[] parameters : listParameters) {
                                boolean same = (parameters.length == method.getParameterTypes().length);
                                for (int p = 0; same && p < parameters.length; p++)
                                    if (!parameters[p].equals(method.getParameterTypes()[p])) {
                                        same = false;
                                        break;
                                    }
                                if (same) {
                                    different = false;
                                    break;
                                }
                            }

                            if (different) {
                                listMember.add(method);
                                listParameters.add(method.getParameterTypes());
                            }
                        }
                }
                clazz = clazz.getSuperclass();
            } catch (Throwable ex) {
                if (ex.getClass().equals(ClassNotFoundException.class)
                        || ex.getClass().equals(NoClassDefFoundError.class))
                    break;
                else
                    throw ex;
            }


            // Hook members
            for (Member member : listMember)
                try {
                    XposedBridge.hookMethod(member, xcMethodHookhook);
                } catch (NoSuchFieldError ex) {
                    LogManager.getInstance().logHookError("hookCommand hookAllMethodByName NoSuchFieldError " + ex.toString());
                } catch (Throwable ex) {
                    LogManager.getInstance().logHookError("hookCommand hookAllMethodByName Throwable " + ex.toString());
                }
        }
    }


    public static String getArgsStr(Object[] args) {
        StringBuffer sb = new StringBuffer();
        for (Object o : args) {
            sb.append(o.getClass().getSimpleName() + "=" + o.toString());
            sb.append(" | ");
        }
        return sb.toString();
    }
}